﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed
#pragma once
#include "GcmpModelInterface.h"
#include "IObject.h"
#include "OwnerPtr.h"
#include <string>

namespace gcmp
{
    class IDocument;

    /// \brief 用户事务
    ///
    /// 不允许嵌套 
    FINAL_INTERFACE class GCMP_MODEL_INTERFACE_EXPORT IUserTransaction : public IObject
    {
    public:
        /// \brief 创建用户事务
        ///
        /// \param pDocument 所在文档
        /// \param name 事务的名字
        /// \param startImmediately 是否立即开始，默认立即启动。不选择立即开始的可以后面通过调用Start()手动启动。
        /// \return OwnerPtr<IUserTransaction> 返回创建出的用户事务。如果选择立即启动但先前事务还未结束，则创建失败，返回空。
        /// \see IsInUserTransaction()
        static OwnerPtr<IUserTransaction> Create(
            IDocument * pDocument,
            const std::wstring& name,
            bool startImmediately = true
        );

        /// \brief 查询是否在事务中
        ///
        /// \param pDocument 文档指针。不允许为空，如果为空返回false。
        /// \param pName 如果在事务中、并且传入非空指针，传出当前事务名称。
        /// \param pId 如果在事务中、并且传入非空指针，传出当前事务编号。
        /// \return bool true表示在事务中;false表示不在事务中。
        /// \see Create()
        static bool IsInUserTransaction(
            const IDocument * pDocument,
            std::wstring * pName = nullptr,
            int32_t * pId = nullptr
        );

        /// \brief 启动事务
        ///
        /// 对Create时立即开始参数设置为false的事务，需要手动Start；否则不需要手动Start。
        /// 对不处于创建但未启动的事务调用Start会有出错提示。
        ///
        /// \return bool 事务启动成功返回true；否则返回false
        /// \see Create
        virtual bool Start(void) = 0;

        /// \brief 提交事务
        ///
        /// 启动了的事务可以提交。提交成功后事务生命周期结束。
        /// 对不处于启动状态的事务调用Commit会有出错提示。
        ///
        /// \return bool 事务提交成功返回true；否则返回false
        /// \see Start
        virtual bool Commit(void) = 0;

        /// \brief 提交事务并且清除历史记录，即不可回退。
        ///
        /// 启动了的事务可以提交。提交成功后事务生命周期结束。
        /// 对不处于启动状态的事务调用Commit会有出错提示。
        ///
        /// \return bool 事务提交成功返回true；否则返回false
        /// \see Start
        /// \note 1) 提交后不能通过Undo回退到之前状态。
        ///       2) 如果崩溃后进行恢复，一旦遇到通过此函数提交的事务，只恢复到此事务提交之前状态，不再继续恢复。
        /// 为能保护用户数据，建议使用此函数时，提示用户保存文件。
        virtual bool CommitAndResetHistory(void) = 0;

        /// \brief 提交事务并且清除历史记录，即不可回退。
        ///
        /// 启动了的事务可以提交。提交成功后事务生命周期结束。
        /// 对不处于启动状态的事务调用Commit会有出错提示。
        ///
        /// \return bool 事务提交成功返回true；否则返回false
        /// \see Start
        /// \note 1) 提交后不能通过Undo回退到之前状态。
        ///       2) 如果崩溃后进行恢复，一旦遇到通过此函数提交的事务，可以恢复到此事务
        ///       3) 不可与CommitAndResetHistory混用。如果在CommitAndResetHistoryWithRecovery之前，
        ///          存在CommitAndResetHistory提交的事务A，崩溃恢复时，A是不被恢复的，所有依赖A的后续操作都会失败。
        ///          所以这种情况下崩溃恢复会失败。
        /// 为能保护用户数据，建议使用此函数时，提示用户保存文件。
        virtual bool CommitAndResetHistoryWithRecovery(void) = 0;

        /// \brief 获取指定文档中未提交的事务
        ///
        /// \param pDocument 指定文档
        /// \param pErrorMessage 错误消息。出错、不为空时返回
        /// \return 事务对象。没有未提交的事务，返回nullptr
        static OwnerPtr<IUserTransaction> GetUncommittedTransaction(
            IDocument* pDocument,
            std::wstring* pErrorMessage
        );

        /// \brief 提交不可重做事务。
        ///
        /// 启动了的事务可以提交，提交后可以通过Undo回退到之前状态，但不能Redo。
        /// 提交成功后事务生命周期结束。
        /// 对不处于启动状态的事务调用Commit会有出错提示。
        ///
        /// \return bool 事务提交成功返回true；否则返回false
        /// \see Start
        virtual bool CommitWithoutRedoCapability(void) = 0;

        /// \brief 回滚事务
        ///
        /// 启动了的事务可以回滚。回滚后事务生命周期结束。
        /// 对不处于启动状态的事务调用Rollback会有出错提示。
        ///
        /// \return bool 事务回滚成功返回true；否则返回false
        /// \see Start
        virtual bool Rollback(void) = 0;

        /// \brief 查询事务是否已经启动
        ///
        /// \return bool 处于启动状态返回true；否则返回false
        /// \see Start
        virtual bool IsStarted(void) const = 0;

        /// \brief 查询事务创建时指定的名字
        ///
        /// \return const std::wstring& 事务名字
        /// \see Create
        virtual const std::wstring& GetName(void) const = 0;

        /// \brief 查询事务的编号，文档内唯一，自增
        /// 
        /// 建议使用文档的RuntimeId和事务编号Id对，来唯一标识事务。
        /// \return 事务编号，负数非法。
        virtual Int32 GetId() const = 0;

        /// \brief 是否开启批处理
        ///
        /// 如果开启批处理，会在事务提交之前统一发送Element PreChange事件，在事务提交后或者回滚统一发送Element PostChange事件
        /// 避免了在事务中，每次修改相同Element都会发送Change事件，节约批量创建Element的时间。
        /// 使用场景：一个事务中对同一Element做了很多次修改，并不关心当前修改的影响，只在事务提交后一个Element发送一次Change事件。
        /// 如果一个事务中对同一Element修改次数比较小，那么该接口就达不到节省时间的效果了。
        ///
        /// \param isBatchProcess 是否批处理，默认为false
        /// \return bool 返回true表示设置成功，否则设置失败
        virtual bool SetIsBatchProcess(bool isBatchProcess) = 0;

    public:
        /// \brief 析构函数
        virtual ~IUserTransaction(void) = 0;
    };
}


